    /** 
    * ALUIDirSecurity -  http://code.google.com/p/alui-toolbox/
    * Copyright (c) 2008-2009
    * by Fabien Sanglier
    *
    * This file is part of ALUIDirSecurity.
    * 
    * ALUIDirSecurity is free software: you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation, either version 3 of the License, or
    * (at your option) any later version.
    * 
    * ALUIDirSecurity is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    * GNU General Public License for more details.
    * 
    * You should have received a copy of the GNU General Public License
    * along with ALUIDirSecurity.  If not, see <http://www.gnu.org/licenses/>.
    *
    */
    
package com.alui.utils;

import com.plumtree.openfoundation.util.XPArrayList;
import com.plumtree.openfoundation.util.XPException;
import com.plumtree.openkernel.config.IOKContext;
import com.plumtree.openkernel.factory.OKConfigFactory;
import com.plumtree.openlog.OpenLogService;
import com.plumtree.openlog.OpenLogger;
import com.plumtree.portaluiinfrastructure.statichelpers.PTDebugHelpers;
import com.plumtree.server.IPTAccessList;
import com.plumtree.server.IPTCard;
import com.plumtree.server.IPTCatalog;
import com.plumtree.server.IPTFolder;
import com.plumtree.server.IPTQueryResult;
import com.plumtree.server.IPTSession;
import com.plumtree.server.PT_FILTEROPS;
import com.plumtree.server.PT_LOCKSTATES;
import com.plumtree.server.PT_PROPIDS;
import com.plumtree.server.PortalObjectsFactory;
import com.plumtree.xpshared.config.ConfigPathResolver;
import java.lang.StringBuffer;

public class FolderSecurityUtil {
	private static OpenLogger log = OpenLogService.GetLogger(OpenLogService.GetComponent("Admin Utilities"),"com.alui.utils.FolderSecurityUtil");
	
	public final static String DEFAULT_APP_NAME = "portal";

	private IPTSession m_ptsession = null;
	private IPTCatalog m_ptCatalog = null;
	private boolean isDebug = false;

	private XPArrayList ptcrawlerids;
	private boolean bShowUnapproved = false;
	
	private int processedcards = 0;
	private int cardprocesserrorcount = 0;
	private long internaltimerbegin = 0;
	private long internaltimerend = 0;
	
	public String ptdocids = ",";
	
	public FolderSecurityUtil(String appName, String username, String password, boolean debug) {
		super();
		
		System.out.println("Start Session Initialization");
		m_ptsession = initSession(appName);
		
		System.out.println("Try to perform the Session Connect");
		
		m_ptsession.Connect(username, password, null);
		System.out.println("Session Connect Successful");
		
		//implement the regexp expression
		isDebug = debug;
		
		m_ptCatalog = m_ptsession.GetCatalog();
	}

	public void addPTCrawlerids(String[] crawlerids) {
		if(crawlerids != null){
			for(int i = 0; i< crawlerids.length; i++){
				addPTCrawlerids(Integer.parseInt(crawlerids[i]));
			}
		}
	}
	
	public long getTimingInMs() {
		return internaltimerend - internaltimerbegin;
	}
	
	public void addPTCrawlerids(int crawlerid) {
		if(ptcrawlerids == null)
			ptcrawlerids = new XPArrayList();
		ptcrawlerids.Add(new Integer(crawlerid));
	}
	
	public int getCardprocesserrorcount() {
		return cardprocesserrorcount;
	}

	public int getProcessedcards() {
		return processedcards;
	}

	public XPArrayList getPTCrawlerids() {
		return ptcrawlerids;
	}

	public void setPTCrawlerids(XPArrayList ptcrawlerids) {
		this.ptcrawlerids = ptcrawlerids;
	}
	
	public boolean isShowUnapproved() {
		return bShowUnapproved;
	}
	
	public void setShowUnapproved(boolean showUnapproved) {
		bShowUnapproved = showUnapproved;
	}

	public FolderSecurityUtil(String appName, String username, String password) {
		this(appName,username,password,false);
	}
	
	public FolderSecurityUtil(String appName, String logintoken, boolean debug) {
		super();
		
		System.out.println("Start Session Initialization");
		m_ptsession = initSession(appName);
		
		System.out.println("Try to perform the Session Connect with the provided token.");
		m_ptsession.Reconnect(logintoken);
		System.out.println("Session Connect Successful");
		
		//implement the regexp expression
		isDebug = debug;
		
		m_ptCatalog = m_ptsession.GetCatalog();
	}
	
	public void Dispose() {
		m_ptsession = null;
	}

	private IPTSession initSession(String sApplicationName) {
		//Initialize OpenKernel, telling OpenConfig where to get it's stuff
		String strServerConfigDir = ConfigPathResolver.GetOpenConfigPath();

		if (sApplicationName == null)
			sApplicationName = DEFAULT_APP_NAME;

		IOKContext configContext = OKConfigFactory.createInstance(
				strServerConfigDir, sApplicationName);
		PortalObjectsFactory.Init(configContext);
		
		//connect using the Portal Server Session
		return PortalObjectsFactory.CreateSession();
	}
	
	public IPTFolder getFolder(int folderid) throws Exception{
		IPTFolder ptFolder = null;
		try
		{
			ptFolder = m_ptCatalog.OpenFolder(folderid, false);
		}
		catch (Exception e)
		{
			System.err.println("An Error occured: " + e.getMessage());
			e.printStackTrace(System.err);
			throw e;
		}
		
		return ptFolder;
	}
	
	public void propagateACLsFromFolder(int folderid, int webpropertyid) throws Exception{
		internaltimerbegin = log.PerformanceBegin();
		
		IPTFolder ptFolder = getFolder(folderid);
		
		System.out.println("Getting ACLs on Folder: " + ptFolder.GetName());
		
		//get the ACLs on the folder
		IPTAccessList ptFolderACLs = ptFolder.GetACL();
		
		//Propagate the folder security on the cards inside the folder
		PropagateACLOnCards(ptFolder, ptFolderACLs, webpropertyid);

		IPTQueryResult folderresults = getFoldersInFolder(ptFolder);
		int nSubFolders = folderresults.RowCount();
		System.out.println("Getting " + nSubFolders + " subfolders...");
		for (int i = 0; i < nSubFolders; i++) {
			System.out.println("Folder Name: " + folderresults.ItemAsString(i, PT_PROPIDS.PT_PROPID_NAME));
			int nFolderID = folderresults.ItemAsInt(i, PT_PROPIDS.PT_PROPID_OBJECTID);
			propagateACLsFromFolder(nFolderID, webpropertyid);
		}
		
		internaltimerend = log.PerformanceBegin();
	}
	
	public IPTQueryResult getCardsInFolder(int folderid) throws Exception {
		return getCardsInFolder(getFolder(folderid));
	}
	
	public IPTQueryResult getCardsInFolder(IPTFolder folder) throws Exception {
		IPTQueryResult qrCards = null;
		try
		{
			/*int nPropIDsForQuery = PT_PROPIDS.PT_PROPID_OBJECTID |
				PT_PROPIDS.PT_PROPID_NAME | PT_PROPIDS.PT_PROPID_CREATED |
				PT_PROPIDS.PT_PROPID_LASTMODIFIED |
				PT_PROPIDS.PT_PROPID_FOLDER_LEVEL;*/
			
			int nPropIDsForQuery = PT_PROPIDS.PT_PROPID_OBJECTID | PT_PROPIDS.PT_PROPID_NAME;
			
			// Apply a filter if needed to include/exclude something
			Object[][] filter = null;
			
			if(null != ptcrawlerids && ptcrawlerids.GetSize() > 0){
				Object[] crawlerIDs = ptcrawlerids.ToArray();
				
				//add filter based on card crawler id
				filter = new Object[3][1];
				filter[0][0]     = new Integer(PT_PROPIDS.PT_PROPID_CARD_CRAWLERID);
				filter[1][0]     = new Integer(PT_FILTEROPS.PT_FILTEROP_IN);
				filter[2][0]     = crawlerIDs;
			}
			
			qrCards = folder.QueryCards(
					nPropIDsForQuery /* prop mask */, 
					bShowUnapproved 	/* include unapproved ?*/,
					PT_PROPIDS.PT_PROPID_OBJECTID 	/* order by */,
					0 		/* no skip rows */,
					-1 		/* no max rows */,
					filter 	/* no query filter */);
			System.out.println("Getting " + qrCards.RowCount() + " cards in folder.");
		}
		catch (Exception e)
		{
			System.err.println("An Error occured: " + e.getMessage());
			e.printStackTrace(System.err);
			throw e;
		}
		
		return qrCards;
	}
	
	public IPTQueryResult getFoldersInFolder(int folderid) throws Exception {
		return getFoldersInFolder(getFolder(folderid));
	}
	
	public IPTQueryResult getFoldersInFolder(IPTFolder folder) throws Exception {
		IPTQueryResult ptqrSubFolders = null;
		try
		{
			// 0 means just this level
			int nLevel = 0;

			/*int nPropIDsForQuery = PT_PROPIDS.PT_PROPID_OBJECTID |
				PT_PROPIDS.PT_PROPID_NAME | PT_PROPIDS.PT_PROPID_CREATED |
				PT_PROPIDS.PT_PROPID_LASTMODIFIED |
				PT_PROPIDS.PT_PROPID_FOLDER_LEVEL;*/
			
			int nPropIDsForQuery = PT_PROPIDS.PT_PROPID_OBJECTID | PT_PROPIDS.PT_PROPID_NAME;
			
			// Apply a filter if needed to exclude something
			Object[][] filter = null;
			
			// query for folders
			ptqrSubFolders = folder.QuerySubfolders(nPropIDsForQuery,
					nLevel, new Integer(PT_PROPIDS.PT_PROPID_NAME), 0, -1,
						filter);
			
			if (null == ptqrSubFolders)
			{
				throw new XPException("Invalid QueryResult supplied, it is null");
			}
		}
		catch (Exception e)
		{
			System.err.println("An Error occured: " + e.getMessage());
			e.printStackTrace(System.err);
			throw e;
		}
		
		return ptqrSubFolders;
	}
	
	public IPTCard removeDupeNames(IPTCard iCard){
		//Jordan - 2/20/09 - Function to remove the (2) from the card name and replace with a space
		
		String curName = iCard.GetName();
		if (curName.indexOf("(2)") > -1) {
			
			int spacePos = curName.indexOf(" ");
			
			if (spacePos > 0) { //only add the space if there is an existing space (more than one word)
				//add in an extra space after the first word so card name will be different in DB
				StringBuffer newName = new StringBuffer(curName).insert(spacePos, " ");
				curName = newName.toString();
				curName = curName.substring(0, curName.length() - 4); //remove the (2)
			}
			
			iCard.SetName(curName); //set newly modified card name
		}
		
		return iCard;
	}
	
	private void PropagateACLOnCards(IPTFolder ptFolder, IPTAccessList ptACL, int webdisplayProp) throws Exception
	{
		System.out.println("Propagating folder ACLs on cards");
		IPTQueryResult qrCards = getCardsInFolder(ptFolder);
		
		IPTCard ptCard = null;
		for (int i=0; i<qrCards.RowCount(); i++)
		{
			System.out.println("Setting Security on Card Object: " + qrCards.ItemAsString(i, PT_PROPIDS.PT_PROPID_NAME));
			
			/* get each card and open server context */
			int id = qrCards.ItemAsInt(i,PT_PROPIDS.PT_PROPID_OBJECTID);
			
			try {
				ptCard = m_ptCatalog.OpenCard(id, true);

				/* get card acl, clear it, and merge empty one with parent acl */
				IPTAccessList ptCardACL = ptCard.GetACL();
				if (ptdocids.indexOf("," + Integer.toString(id) + ",") == -1) {
					//only clear completely if the card has not already been accessed
					ptCardACL.ClearCompletely();
					
					//remove the (2) from the card name if neccessary
					ptCard = removeDupeNames(ptCard);
					
					//add card ID to list of IDs
					ptdocids = ptdocids + Integer.toString(id) + ",";
				}		
				
                ptCardACL.Merge(ptACL);
				
                if(webdisplayProp != -1) {
                    if (ptCard.GetPropertyValues().GetItem(webdisplayProp) != null){
                        ptCard.GetPropertyValues().GetItem(webdisplayProp).SetFieldValue("New Window");
                    } else {
                        ptCard.GetPropertyValues().Add(webdisplayProp).SetFieldValue("New Window");
                    }
                }
                
				// store the card
				ptCard.Store();
				processedcards++;
				System.out.println("Card Security Successfully set!");
			} catch (Exception exc) {
				cardprocesserrorcount++;
				System.err.println("An Error Occured While setting security on card: " + exc);
				throw exc;
			} finally {
				if(ptCard.GetLockState() == PT_LOCKSTATES.PT_LOCKED)
					ptCard.UnlockObject();
			}
		}
	}
}
